


<!DOCTYPE html>
<html lang="zh-CN">
  <head><meta name="generator" content="Hexo 3.8.0">
    <title>Packaging Vue Components for npm — Vue.js</title>
    <meta charset="utf-8">
    <meta name="description" content="Vue.js - The Progressive JavaScript Framework">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="alternate" hreflang="x-default" href="https://vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="zh" href="packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="ja" href="https://jp.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="ru" href="https://ru.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="ko" href="https://kr.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="pt-BR" href="https://br.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">
    <link rel="alternate" hreflang="fr" href="https://fr.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html">

    <meta property="og:type" content="article">
    <meta property="og:title" content="Packaging Vue Components for npm — Vue.js">
    <meta property="og:description" content="Vue.js - The Progressive JavaScript Framework">
    <meta property="og:image" content="https://cn.vuejs.org//images/logo.png">

    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="Packaging Vue Components for npm — Vue.js">
    <meta name="twitter:description" content="Vue.js - The Progressive JavaScript Framework">
    <meta name="twitter:image" content="https://cn.vuejs.org/images/logo.png">

    <link rel="apple-touch-icon" sizes="57x57" href="../../images/icons/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="../../images/icons/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="../../images/icons/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="../../images/icons/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="../../images/icons/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="../../images/icons/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="../../images/icons/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="../../images/icons/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="../../images/icons/apple-icon-180x180.png">
    <link rel="icon" type="image/png" sizes="192x192" href="../../images/icons/android-icon-192x192.png">
    <link rel="icon" type="image/png" sizes="32x32" href="../../images/icons/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="96x96" href="../../images/icons/favicon-96x96.png">
    <link rel="icon" type="image/png" sizes="16x16" href="../../images/icons/favicon-16x16.png">
    <meta name="msapplication-TileImage" content="/images/icons/ms-icon-144x144.png">
    <link rel="icon" href="../../images/logo.png" type="image/png">

    <meta name="msapplication-TileColor" content="#4fc08d">
    <meta name="theme-color" content="#4fc08d">

    <meta name="msapplication-config" content="browserconfig.xml">
    <link rel="manifest" href="../../manifest.json">

    <!-- <link href="https://fonts.googleapis.com" rel="preconnect" crossorigin> -->
    <!-- <link href="https://fonts.gstatic.com" rel="preconnect" crossorigin> -->
    <!-- <link href="https://maxcdn.bootstrapcdn.com" rel="preconnect" crossorigin> -->

    <!-- <link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600|Roboto Mono' rel='stylesheet' type='text/css'> -->
    <!-- <link href='//fonts.googleapis.com/css?family=Dosis:500&text=Vue.js' rel='stylesheet' type='text/css'> -->

    <link href="https://code.bdstatic.com/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">

    <!-- main page styles -->
    <link rel="stylesheet" href="../../css/page.css">

    <!-- this needs to be loaded before guide's inline scripts -->
    <script src="../../js/vue.js"></script>

    

    <script>
      Vue.config.productionTip = false
      window.PAGE_TYPE = "cookbook"
    </script>

    <!-- ga -->
    <script>
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-46852172-3', 'cn.vuejs.org');
      ga('send', 'pageview');
    </script>
  </head>
  <body class="docs">
    <div id="mobile-bar">
      <a class="menu-button"></a>
      <a class="logo" href="../../index.html"></a>
    </div>
    <div id="header">
  <a id="logo" href="../../index.html">
    <img src="../../images/logo.png" alt="vue logo">
    <span>Vue.js</span>
  </a>
  <ul id="nav">
    <li>
  <form id="search-form">
    <input type="text" id="search-query-nav" class="search-query st-default-search-input" aria-label="搜索">
  </form>
</li>
<li class="nav-dropdown-container learn">
  <a class="nav-link current">学习</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><h4>文档</h4></li>
    <li>
      <ul>
        <li><a href="../guide/index.html" class="nav-link">教程</a></li>
        <li><a href="../api/index.html" class="nav-link">API</a></li>
        <li><a href="../style-guide/index.html" class="nav-link">风格指南</a></li>
        <li><a href="../examples/index.html" class="nav-link">示例</a></li>
        <li><a href="index.html" class="nav-link current">Cookbook</a></li>
      </ul>
    </li>
    <li><h4>视频教程</h4></li>
    <li>
      <ul>
        <li><a href="https://www.vuemastery.com/courses/" class="nav-link" target="_blank" rel="sponsored noopener">Vue Mastery (英文)</a></li>
        <li><a href="https://vueschool.io/?friend=vuejs&amp;utm_source=Vuejs.org&amp;utm_medium=Link&amp;utm_content=Navbar%20Dropdown" class="nav-link" target="_blank" rel="noopener">Vue School (英文)</a></li>
        <li><a href="https://learning.dcloud.io/" class="nav-link" target="_blank" rel="sponsored noopener">DCloud 视频教程</a></li>
      </ul>
    </li>
  </ul>
</li>

<li class="nav-dropdown-container ecosystem">
  <a class="nav-link">生态系统</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><h4>帮助</h4></li>
    <li><ul>
      <li><a href="https://forum.vuejs.org/" class="nav-link" target="_blank" rel="noopener">论坛</a></li>
      <li><a href="https://chat.vuejs.org/" class="nav-link" target="_blank" rel="noopener">聊天室</a></li>
      <li><a href="https://events.vuejs.org/meetups/" class="nav-link" target="_blank" rel="noopener">聚会</a></li>
    </ul></li>
    <li><h4>工具</h4></li>
    <li>
      <ul>
        <li><a href="https://github.com/vuejs/vue-devtools" class="nav-link" target="_blank" rel="noopener">Devtools</a></li>
        <li><a href="https://cli.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue CLI</a></li>
        <li><a href="https://vue-loader.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue Loader</a></li>
      </ul>
    </li>
    <li><h4>核心插件</h4></li>
    <li><ul>
      <li><a href="https://router.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue Router</a></li>
      <li><a href="https://vuex.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vuex</a></li>
      <li><a href="https://ssr.vuejs.org/zh/" class="nav-link" target="_blank" rel="noopener">Vue 服务端渲染</a></li>
    </ul></li>
    <li><h4>信息</h4></li>
    <li><ul>
      <li><a href="https://news.vuejs.org" class="nav-link" target="_blank" rel="noopener">周刊</a></li>
      <li><a href="https://github.com/vuejs/vue/projects/6" class="nav-link" target="_blank" rel="noopener">Roadmap</a></li>
      <li><a href="https://events.vuejs.org/" class="nav-link" target="_blank" rel="noopener">活动</a></li>
      <li><a href="https://twitter.com/vuejs" class="nav-link" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://medium.com/the-vue-point" class="nav-link" target="_blank" rel="noopener">博客</a></li>
      <li><a href="https://vuejobs.com/?ref=vuejs" class="nav-link" target="_blank" rel="noopener">工作</a></li>
    </ul></li>
  </ul>
</li>

<li>
  <a href="../guide/team.html" class="nav-link team">团队</a>
</li>
<li class="nav-dropdown-container resources">
  <a href="#" class="nav-link">资源列表</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="../../resources/partners.html" class="nav-link">合作伙伴</a></li>
    <li><a href="../../resources/themes.html" class="nav-link">主题</a></li>
    <li><a href="https://github.com/vuejs/awesome-vue" class="nav-link" target="_blank">Awesome Vue</a></li>
  </ul>
</li>

<!-- <li>
  <a href="/partners" class="nav-link ">Partners</a>
</li> -->
<li class="nav-dropdown-container support-vue">
  <a href="../../support-vuejs/index.html" class="nav-link">支持 Vue</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="../../support-vuejs/index.html#One-time-Donations" class="nav-link">一次性赞助</a></li>
    <li><a href="../../support-vuejs/index.html#Recurring-Pledges" class="nav-link">周期性赞助</a></li>
    <li><a href="https://www.smallsticker.com/%E8%B4%B4%E7%BA%B8/vue.html" rel="noopener" class="nav-link">贴纸</a></li>
    <li><a href="https://osholic.com/?utm_source=vue&amp;utm_medium=dropdown" rel="noopener" class="nav-link">周边</a></li>
    <li><a href="https://vue.threadless.com" target="_blank" rel="noopener" class="nav-link">T 恤商店</a></li>
  </ul>
</li>

<li class="nav-dropdown-container language">
  <a class="nav-link">多语言</a><span class="arrow"></span>
  <ul class="nav-dropdown">
    <li><a href="https://vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">English</a></li>
    <li><a href="https://jp.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">日本語</a></li>
    <li><a href="https://ru.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">Русский</a></li>
    <li><a href="https://kr.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">한국어</a></li>
    <li><a href="https://br.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">Português</a></li>
    <li><a href="https://fr.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">Français</a></li>
    <li><a href="https://vi.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html" class="nav-link" target="_blank" rel="noopener">Tiếng Việt</a></li>
  </ul>
</li>

<li><a href="https://github.com/vuejs/cn.vuejs.org/" target="_blank" class="nav-link contribute">参与翻译</a></li>

  </ul>
</div>

    
      <div id="main" class="fix-sidebar">
        
          
  

<div class="sidebar">
  <div class="sidebar-inner">
    
    <div class="list">
      <div id="sidebar-sponsors-special">
  <div class="main-sponsor">
    <span>特别赞助商</span>
    <div>
    <a href="http://www.dcloud.io/?hmsr=vuejsorg&amp;hmpl=&amp;hmcu=&amp;hmkw=&amp;hmci=" target="_blank" rel="sponsored noopener" class="logo">
      <img src="../../images/dcloud.gif" alt="">
    </a>
    </div>
    <div>
    <a href="https://youzan.github.io/vant?source=vuejsorg" target="_blank" rel="sponsored noopener" class="logo">
      <img src="../../images/vant.png" alt="">
    </a>
    </div>
  </div>
</div>
<!--

<div id="sidebar-sponsors-platinum-left">
  <div class="main-sponsor">
    <span>白金赞助商</span>
    <div>
    <a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/vueschool.png" alt="VueSchool">
    </a>
    <a href="https://vehikl.com/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/vehikl.png" alt="Vehikl">
    </a>
    <a href="https://www.nativescript.org/vue?utm_source=vue-js-org&utm_medium=website&utm_campaign=nativescript-awareness" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/nativescript.png" alt="NativeScript">
    </a>
    <a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/retool.png" alt="Retool">
    </a>
    </div>
  </div>
  <a class="become-backer" href="/support-vuejs">
    成为赞助者
  </a>
</div>


-->

      
        <h2>
          
          Cookbook<sup class="beta">beta</sup>
          
        </h2>
        <ul class="menu-root">
  
    
    
    <li>
      <a href="index.html" class="sidebar-link">介绍</a>
    </li>
  
    
    
    <li>
      <a href="adding-instance-properties.html" class="sidebar-link">添加实例属性</a>
    </li>
  
    
    
    <li>
      <a href="form-validation.html" class="sidebar-link">表单校验</a>
    </li>
  
    
    
    <li>
      <a href="editable-svg-icons.html" class="sidebar-link">可编辑的 SVG 图标系统</a>
    </li>
  
    
    
    <li>
      <a href="serverless-blog.html" class="sidebar-link">创建一个基于 CMS 的博客</a>
    </li>
  
    
    
    <li>
      <a href="unit-testing-vue-components.html" class="sidebar-link">Vue 组件的单元测试</a>
    </li>
  
    
    
    <li>
      <a href="creating-custom-scroll-directives.html" class="sidebar-link">创建自定义滚动指令</a>
    </li>
  
    
    
    <li>
      <a href="debugging-in-vscode.html" class="sidebar-link">在 VS Code 中调试</a>
    </li>
  
    
    
    <li>
      <a href="using-axios-to-consume-apis.html" class="sidebar-link">使用 axios 访问 API</a>
    </li>
  
    
    
    <li>
      <a href="avoiding-memory-leaks.html" class="sidebar-link">避免内存泄漏</a>
    </li>
  
    
    
    <li>
      <a href="client-side-storage.html" class="sidebar-link">客户端存储</a>
    </li>
  
    
    
    <li>
      <a href="packaging-sfc-for-npm.html" class="sidebar-link current">Packaging Vue Components for npm</a>
    </li>
  
    
    
    <li>
      <a href="dockerize-vuejs-app.html" class="sidebar-link">Dockerize Vue.js App</a>
    </li>
  
    
    
    <li>
      <a href="practical-use-of-scoped-slots.html" class="sidebar-link">Practical use of scoped slots with GoogleMaps</a>
    </li>
  
</ul>

      
    </div>
  </div>
</div>
<!--

<div id="sidebar-sponsors-platinum-right">
  <div class="main-sponsor">
    <span>白金赞助商</span>
    <div>
    <a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/vueschool.png" alt="VueSchool">
    </a>
    <a href="https://vehikl.com/" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/vehikl.png" alt="Vehikl">
    </a>
    <a href="https://www.nativescript.org/vue?utm_source=vue-js-org&utm_medium=website&utm_campaign=nativescript-awareness" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/nativescript.png" alt="NativeScript">
    </a>
    <a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank" rel="sponsored noopener" class="logo">
      <img src="/images/retool.png" alt="Retool">
    </a>
    </div>
  </div>
  <a class="become-backer" href="/support-vuejs">
    成为赞助者
  </a>
</div>


-->


<div class="content cookbook with-sidebar ">
  
    
      
<div id="ad">
  <span style="float: right;">广告</span>
  <a href="https://time.geekbang.org/column/intro/216?code=mM%2FdqOPks0VQ7EkYGPNisoEpHDsb0ViHBXYa%2Fyg02k8%3D&amp;utm_term=SPoster" target="_blank" rel="sponsored noopener">
    <img src="../../images/geekbang-ad.jpg">
  </a>
  <!-- <a href="https://ke.qq.com/course/392130?saleToken=992600&from=pclink" target="_blank" rel="sponsored noopener">
    <img src="/images/tencent-ad.png">
  </a> -->
  <!-- <script
    async
    type="text/javascript"
    src="//cdn.carbonads.com/carbon.js?serve=CKYIK2QU&placement=vuejsorg"
    id="_carbonads_js">
  </script> -->
</div>


    
  
  
    <h1>Packaging Vue Components for npm</h1>
  

  <div class="ad-pagetop">
  <a href="http://www.tp-shop.cn/index.php?http_referer=vuejs" target="_blank" rel="noopener noreferrer">
    <span class="name">TPshop</span>
    <span class="description">中国免费商城系统 - 搜豹商城系统 - 免费50小时Vue视频教程</span>
    <span class="action">立即查看 &gt;</span>
  </a>
</div>


  
    <h2 id="Base-Example"><a href="#Base-Example" class="headerlink" title="Base Example"></a>Base Example</h2><p>Vue components by nature are meant to be re-used. This is easy when the component is only used within a single application. But how can you write a component once and use it in multiple sites/applications? Perhaps the easiest solution is via npm.</p>
<p>By packaging your component to be shared via npm, it can be imported/required into a build process for use in full-fledged web applications:</p>
<pre><code class="hljs js"><span class="hljs-keyword">import</span> MyComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'my-component'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
  <span class="hljs-attr">components</span>: &#123;
    MyComponent,
  &#125;,
  <span class="hljs-comment">// rest of the component</span>
&#125;</code></pre>
<p>Or even used via <code>&lt;script&gt;</code> tag in the browser directly:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/my-component"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
...
<span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span>
...</code></pre>
<p>Not only does this help you avoid copy/pasting components around, but it also allows you to give back to the Vue community!</p>
<h2 id="Can’t-I-Just-Share-vue-Files-Directly"><a href="#Can%E2%80%99t-I-Just-Share-vue-Files-Directly" class="headerlink" title="Can’t I Just Share .vue Files Directly?"></a>Can’t I Just Share <code>.vue</code> Files Directly?</h2><p>Vue already allows components to be written as a single file. Because a Single File Component (SFC) is already just one file, you might ask:</p>
<blockquote>
<p>“Why can’t people use my <code>.vue</code> file directly? Isn’t that the simplest way to share components?”</p>
</blockquote>
<p>It’s true, you can share <code>.vue</code> files directly, and anyone using a <a href="https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds" target="_blank" rel="noopener">Vue build</a> containing the Vue compiler can consume it immediately. Also, the SSR build uses string concatenation as an optimization, so the <code>.vue</code> file might be preferred in this scenario (see <a href="#SSR-Usage">Packaging Components for npm &gt; SSR Usage</a> for details). However, this excludes anyone who wishes to use the component directly in a browser via <code>&lt;script&gt;</code> tag, anyone who uses a runtime-only build, or build processes which don’t understand what to do with <code>.vue</code> files.</p>
<p>Properly packaging your SFC for distribution via npm enables your component to be shared in a way which is ready to use everywhere!</p>
<h2 id="Packaging-Components-for-npm"><a href="#Packaging-Components-for-npm" class="headerlink" title="Packaging Components for npm"></a>Packaging Components for npm</h2><p>For the purposes of this section, assume the following file structure:</p>
<pre><code class="hljs undefined">package.json
build/
   rollup.config.js
src/
   wrapper.js
   my-component.vue
dist/</code></pre>
<p class="tip">Throughout this document, references are made to the package.json file listed above. The file used in these examples was generated by hand, and will include the minimum configuration required for the discussion/task at hand. It is likely your own package.json file will contain a lot more than is listed here.</p>

<h3 id="How-does-npm-know-which-version-to-serve-to-a-browser-build-process"><a href="#How-does-npm-know-which-version-to-serve-to-a-browser-build-process" class="headerlink" title="How does npm know which version to serve to a browser/build process?"></a>How does npm know which version to serve to a browser/build process?</h3><p>The package.json file used by npm really only requires one version (<code>main</code>), but as it turns out, we aren’t limited to that. We can address the most common use cases by specifying 2 additional versions (<code>module</code> and <code>unpkg</code>), and provide access to the <code>.vue</code> file itself using the <code>browser</code> field. A sample package.json would look like this:</p>
<pre><code class="hljs json">&#123;
  "name": "my-component",
  "version": "1.2.3",
  "main": "dist/my-component.umd.js",
  "module": "dist/my-component.esm.js",
  "unpkg": "dist/my-component.min.js",
  "browser": &#123;
    "./sfc": "src/my-component.vue"
  &#125;,
  ...
&#125;</code></pre>
<p>When webpack 2+, Rollup, or other modern build tools are used, they will pick up on the <code>module</code> build. Legacy applications would use the <code>main</code> build, and the <code>unpkg</code> build can be used directly in browsers. In fact, the <a href="https://unpkg.com" target="_blank" rel="noopener">unpkg</a> cdn automatically uses this when someone enters the URL for your module into their service!</p>
<h3 id="SSR-Usage"><a href="#SSR-Usage" class="headerlink" title="SSR Usage"></a>SSR Usage</h3><p>You might have noticed something interesting - browsers aren’t going to be using the <code>browser</code> version. That’s because this field is actually intended to allow authors to provide <a href="https://github.com/defunctzombie/package-browser-field-spec#spec" target="_blank" rel="noopener">hints to bundlers</a> which in turn create their own packages for client side use. With a little creativity, this field allows us to map an alias to the <code>.vue</code> file itself. For example:</p>
<pre><code class="hljs js"><span class="hljs-keyword">import</span> MyComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'my-component/sfc'</span>; <span class="hljs-comment">// Note the '/sfc'</span></code></pre>
<p>Compatible bundlers see the <code>browser</code> definition in package.json and translate requests for <code>my-component/sfc</code> into <code>my-component/src/my-component.vue</code>, resulting in the original <code>.vue</code> file being used instead. Now the SSR process can use the string concatenation optimizations it needs to for a boost in performance.</p>
<p class="tip">Note: When using <code>.vue</code> components directly, pay attention to any type of pre-processing required by <code>script</code> and <code>style</code> tags. These dependencies will be passed on to users. Consider providing ‘plain’ SFCs to keep things as light as possible.</p>

<h3 id="How-do-I-make-multiple-versions-of-my-component"><a href="#How-do-I-make-multiple-versions-of-my-component" class="headerlink" title="How do I make multiple versions of my component?"></a>How do I make multiple versions of my component?</h3><p>There is no need to write your module multiple times. It is possible to prepare all 3 versions of your module in one step, in a matter of seconds. The example here uses <a href="https://rollupjs.org" target="_blank" rel="noopener">Rollup</a> due to its minimal configuration, but similar configuration is possible with other build tools - more details on this decision can be found <a href="https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c" target="_blank" rel="noopener">here</a>. The package.json <code>scripts</code> section can be updated with a single entry for each build target, and a more generic <code>build</code> script that runs them all in one pass. The sample package.json file now looks like this:</p>
<pre><code class="hljs json">&#123;
  "name": "my-component",
  "version": "1.2.3",
  "main": "dist/my-component.umd.js",
  "module": "dist/my-component.esm.js",
  "unpkg": "dist/my-component.min.js",
  "browser": &#123;
    "./sfc": "src/my-component.vue"
  &#125;,
  "scripts": &#123;
    "build": "npm run build:umd &amp; npm run build:es &amp; npm run build:unpkg",
    "build:umd": "rollup --config build/rollup.config.js --format umd --file dist/my-component.umd.js",
    "build:es": "rollup --config build/rollup.config.js --format es --file dist/my-component.esm.js",
    "build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/my-component.min.js"
  &#125;,
  "devDependencies": &#123;
    "rollup": "^1.17.0",
    "rollup-plugin-buble": "^0.19.8",
    "rollup-plugin-commonjs": "^10.0.1",
    "rollup-plugin-vue": "^5.0.1",
    "vue": "^2.6.10",
    "vue-template-compiler": "^2.6.10"
    ...
  &#125;,
  ...
&#125;</code></pre>
<p class="tip">Remember, if you have an existing package.json file, it will likely contain a lot more than this one does. This merely illustrates a starting point. Also, the <i>packages</i> listed in devDependencies (not their versions) are the minimum requirements for rollup to create the three separate builds (umd, es, and unpkg) mentioned. As newer versions become available, they should be updated as necessary.</p>

<p>Our changes to package.json are complete. Next, we need a small wrapper to export/auto-install the actual SFC, plus a minimal Rollup configuration, and we’re set!</p>
<h3 id="What-does-my-packaged-component-look-like"><a href="#What-does-my-packaged-component-look-like" class="headerlink" title="What does my packaged component look like?"></a>What does my packaged component look like?</h3><p>Depending on how your component is being used, it needs to be exposed as either a <a href="https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc#c33a" target="_blank" rel="noopener">CommonJS/UMD</a> javascript module, an <a href="https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc#4f5e" target="_blank" rel="noopener">ES6 javascript</a> module, or in the case of a <code>&lt;script&gt;</code> tag, it will be automatically loaded into Vue via <code>Vue.use(...)</code> so it’s immediately available to the page. This is accomplished by a simple wrapper.js file which handles the module export and auto-install. That wrapper, in its entirety, looks like this:</p>
<pre><code class="hljs js"><span class="hljs-comment">// Import vue component</span>
<span class="hljs-keyword">import</span> component <span class="hljs-keyword">from</span> <span class="hljs-string">'./my-component.vue'</span>;

<span class="hljs-comment">// Declare install function executed by Vue.use()</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">install</span>(<span class="hljs-params">Vue</span>) </span>&#123;
	<span class="hljs-keyword">if</span> (install.installed) <span class="hljs-keyword">return</span>;
	install.installed = <span class="hljs-literal">true</span>;
	Vue.component(<span class="hljs-string">'MyComponent'</span>, component);
&#125;

<span class="hljs-comment">// Create module definition for Vue.use()</span>
<span class="hljs-keyword">const</span> plugin = &#123;
	install,
&#125;;

<span class="hljs-comment">// Auto-install when vue is found (eg. in browser via &lt;script&gt; tag)</span>
<span class="hljs-keyword">let</span> GlobalVue = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">'undefined'</span>) &#123;
	GlobalVue = <span class="hljs-built_in">window</span>.Vue;
&#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> global !== <span class="hljs-string">'undefined'</span>) &#123;
	GlobalVue = global.Vue;
&#125;
<span class="hljs-keyword">if</span> (GlobalVue) &#123;
	GlobalVue.use(plugin);
&#125;

<span class="hljs-comment">// To allow use as module (npm/webpack/etc.) export component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> component;</code></pre>
<p>Notice the first line directly imports your SFC, and the last line exports it unchanged. As indicated by the comments in the rest of the code, the wrapper provides an <code>install</code> function for Vue, then attempts to detect Vue and automatically install the component. With 90% of the work done, it’s time to sprint to the finish!</p>
<h3 id="How-do-I-configure-the-Rollup-build"><a href="#How-do-I-configure-the-Rollup-build" class="headerlink" title="How do I configure the Rollup build?"></a>How do I configure the Rollup build?</h3><p>With the package.json <code>scripts</code> section ready and the SFC wrapper in place, all that is left is to ensure Rollup is properly configured. Fortunately, this can be done with a small 16 line rollup.config.js file:</p>
<pre><code class="hljs js"><span class="hljs-keyword">import</span> commonjs <span class="hljs-keyword">from</span> <span class="hljs-string">'rollup-plugin-commonjs'</span>; <span class="hljs-comment">// Convert CommonJS modules to ES6</span>
<span class="hljs-keyword">import</span> vue <span class="hljs-keyword">from</span> <span class="hljs-string">'rollup-plugin-vue'</span>; <span class="hljs-comment">// Handle .vue SFC files</span>
<span class="hljs-keyword">import</span> buble <span class="hljs-keyword">from</span> <span class="hljs-string">'rollup-plugin-buble'</span>; <span class="hljs-comment">// Transpile/polyfill with reasonable browser support</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;
    <span class="hljs-attr">input</span>: <span class="hljs-string">'src/wrapper.js'</span>, <span class="hljs-comment">// Path relative to package.json</span>
    output: &#123;
        <span class="hljs-attr">name</span>: <span class="hljs-string">'MyComponent'</span>,
        <span class="hljs-attr">exports</span>: <span class="hljs-string">'named'</span>,
    &#125;,
    <span class="hljs-attr">plugins</span>: [
        commonjs(),
        vue(&#123;
            <span class="hljs-attr">css</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Dynamically inject css as a &lt;style&gt; tag</span>
            compileTemplate: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Explicitly convert template to render function</span>
        &#125;),
        buble(), <span class="hljs-comment">// Transpile to ES5</span>
    ],
&#125;;</code></pre>
<p>This sample config file contains the minimum settings to package your SFC for npm. There is room for customization, such as extracting CSS to a separate file, using a CSS preprocessor, uglifying the JS output, etc.</p>
<p>Also, it is worth noting the <code>name</code> given the component here. This is a PascalCase name that the component will be given, and should correspond with the kebab-case name used elsewhere throughout this recipe.</p>
<h3 id="Will-this-replace-my-current-development-process"><a href="#Will-this-replace-my-current-development-process" class="headerlink" title="Will this replace my current development process?"></a>Will this replace my current development process?</h3><p>The configuration here is not meant to replace the development process that you currently use. If you currently have a webpack setup with hot module reloading (HMR), keep using it! If you’re starting from scratch, feel free to install <a href="https://github.com/vuejs/vue-cli/" target="_blank" rel="noopener">Vue CLI 3</a>, which will give you the whole HMR experience config free:</p>
<pre><code class="hljs bash">vue serve --open src/my-component.vue</code></pre>
<p>In other words, do all of your development in whatever way you are comfortable. The things outlined in this recipe are more like ‘finishing touches’ than a full dev process.</p>
<h2 id="When-to-Avoid-this-Pattern"><a href="#When-to-Avoid-this-Pattern" class="headerlink" title="When to Avoid this Pattern"></a>When to Avoid this Pattern</h2><p>Packaging SFCs in this manner might not be a good idea in certain scenarios. This recipe doesn’t go into detail on how the components themselves are written. Some components might provide side effects like directives, or extend other libraries with additional functionality. In those cases, you will need to evaluate whether or not the changes required to this recipe are too extensive.</p>
<p>In addition, pay attention to any dependencies that your SFC might have. For example, if you require a third party library for sorting or communication with an API, Rollup might roll those packages into the final code if not properly configured. To continue using this recipe, you would need to configure Rollup to exclude those files from the output, then update your documentation to inform your users about these dependencies.</p>
<h2 id="Alternative-Patterns"><a href="#Alternative-Patterns" class="headerlink" title="Alternative Patterns"></a>Alternative Patterns</h2><p>At the time this recipe was written, Vue CLI 3 was itself in beta. This version of the CLI comes with a built-in <code>library</code> build mode, which creates CommonJS and UMD versions of a component. This might be adequate for your use cases, though you will still need to make sure your package.json file points to <code>main</code> and <code>unpkg</code> properly. Also, there will be no ES6 <code>module</code> output unless that capability is added to the CLI before its release or via plugin.</p>
<h2 id="Acknowledgements"><a href="#Acknowledgements" class="headerlink" title="Acknowledgements"></a>Acknowledgements</h2><p>This recipe is the result of a lightning talk given by <a href="https://twitter.com/webdevdodge" target="_blank" rel="noopener">Mike Dodge</a> at VueConf.us in March 2018. He has published a utility to npm which will quickly scaffold a sample SFC using this recipe. You can download the utility, <a href="https://www.npmjs.com/package/vue-sfc-rollup" target="_blank" rel="noopener">vue-sfc-rollup</a>, from npm. You can also <a href="https://github.com/team-innovation/vue-sfc-rollup" target="_blank" rel="noopener">clone the repo</a> and customize it.</p>

  
  
  <div class="footer">
      <script src="https://m.servedby-buysellads.com/monetization.js" type="text/javascript"></script>
<div id="bsa-native"></div>
<script>
_bsa.init('custom', 'CKYD62QM', 'placement:vuejsorg',
  {
    target: '#bsa-native',
    template: '<a class="native-box" href="##statlink##"><div class="native-sponsor">Sponsor</div><div class="native-text"><strong>##company##</strong> — ##description##</div></a>'
  }
);
</script>


    发现错误？想参与编辑？
    <a href="https://github.com/vuejs/cn.vuejs.org/blob/master/src/v2/cookbook/packaging-sfc-for-npm.md" rel="noopener" target="_blank">
      在 GitHub 上编辑此页！
    </a>
  </div>
</div>

        
      </div>
      <script src="../../js/smooth-scroll.min.js"></script>
    

    <!-- main custom script for sidebars, version selects etc. -->
    <script src="../../js/css.escape.js"></script>
    <script src="../../js/common.js"></script>

    <!-- search -->
    <link href="https://code.bdstatic.com/npm/docsearch.js@1.5.0/dist/cdn/docsearch.min.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="../../css/search.css">
    <script src="https://code.bdstatic.com/npm/docsearch.js@1.5.0/dist/cdn/docsearch.min.js"></script>
    <script>
    [
      '#search-query-nav',
      '#search-query-sidebar',
      '#search-query-menu'
    ].forEach(function (selector) {
      if (!document.querySelector(selector)) return
      // search index defaults to v2
      var match = window.location.pathname.match(/^\/(v\d+)/)
      var version = match ? match[1] : 'v2'
      docsearch({
      appId: 'BH4D9OD16A',
      apiKey: '5638280abff9d207417bb03be05f0b25',
      indexName: 'vuejs_cn2',
      inputSelector: selector,
      algoliaOptions: { facetFilters: ["version:" + version] },
      autocompleteOptions: { hint: false, appendTo: 'body'}
      })
    })
    </script>
  </body>
</html>
